package com.gopay.bis.spdb.adpay.operation;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.gopay.common.cipher.utils.LoggerMaskUtils;

/**
 * Socket请求类
 * 
 * @SocketTransport.java
 * @author LEO
 * @2012-8-8 上午10:44:11 www.gopay.com.cn Inc.All rights reserved.
 */
public class SocketTransport {
    protected Log logger = LogFactory.getLog(this.getClass());

    /** socket客户端 ***/
    private Socket socketClient = null;

    // 请求地址
    private String host;
    // 请求端口
    private int port;
    // 超时时间
    private int timeout = 10000;
    // 接收块大小
    private int receiveBufferSize;
    // 发送块大小
    private int sendBufferSize;

    /***
     * 与银行交易
     * 
     * @throws SocketException
     * @throws SocketTimeoutException
     */
    public String submit(Object obj) {
        socketClient = getSocket();
        String result = null;

        if (socketClient != null) {
            try {
                result = sendAndGetDataFromBankDL(socketClient, obj);
            } catch (Exception e) {
                logger.error("SocketTransport submit:", e);
            }
        }

        return result;
    }

    /**
     * 与银行换取连接socket
     * 
     * @return
     * @throws SocketException
     * @throws SocketTimeoutException
     */
    private Socket getSocket() {
        Socket socket = null;
        try {
            socket = new Socket(host, port);
            socket.setSoTimeout(timeout);
            logger.error("~~~~timeout:" + timeout);
            socket.setReceiveBufferSize(receiveBufferSize);
            socket.setSendBufferSize(sendBufferSize);
        } catch (SocketTimeoutException e) {
            logger.error("Connection scoket error:", e);
        } catch (SocketException e) {
            logger.error("Connection scoket error:", e);
        } catch (Exception e) {
            logger.error("Connection scoket error:", e);
        }
        return socket;
    }

    /**
     * socket通信 发送和接收报文
     * 
     * @param client
     * @param obj
     * @return String
     * @throws Exception 
     */
    private String sendAndGetDataFromBankDL(Socket client, Object obj) {
    	String reqXml = (String)obj;
    	
    	
        DataOutputStream out = null;
        byte[] b_respContext = null;
        String tradeContext = null; 
        try {
            // 提交报文
        	
        	int len = reqXml.getBytes("GBK").length;
            out = new DataOutputStream(client.getOutputStream());
            logger.error("SocketTransport Sent Data start: \n" + LoggerMaskUtils.maskString(reqXml));
            out.write(int2byte(len, 8));
            out.write(reqXml.getBytes("GBK"));
            out.flush();
        	/*out = new DataOutputStream(client.getOutputStream());
        	OutputStreamWriter outSW = new OutputStreamWriter(out, "GBK");  
            BufferedWriter bw = new BufferedWriter(outSW);
            logger.error("SocketTransport Sent Data start: \n");
            bw.write(new String((byte[]) obj,"GBK"));
            bw.flush();*/

            logger.error("send url:" + host + ":" + port);
            // 接收返回内容
            InputStream in = client.getInputStream();
			//获取报文总长度
            byte [] b_totalLength = new byte[8];
            in.read(b_totalLength);
				
			int totalLength = byte2int(b_totalLength);
			System.out.println("返回报文总长度为："+totalLength);
			//根据报文总长度创建数组用于接收报文
			b_respContext = new byte[totalLength];
			
			//获取报文正文
			int readLength = 0,off = 0,left = totalLength;
			int tempLength = 1024;
			byte [] tempByte = new byte[tempLength];
			while(left>0){
				int realLength = Math.min(tempLength, left);
				readLength = in.read(tempByte,0,realLength);
				if(readLength==-1){
					break;
				}
				System.arraycopy(tempByte, 0, b_respContext, off, readLength);
				off+=readLength;
				left-=readLength;
			}
			tradeContext = new String(b_respContext,"GBK");
			client.shutdownInput();
            
            logger.error("SocketTransport the receive data length:" + totalLength);
        } catch (IOException e) {
            logger.error("SocketTransport sendAndGetDataFromBankDL:", e);
        } catch (Exception e) {
        	logger.error("SocketTransport sendAndGetDataFromBankDL:", e);
		} finally {
            
            try {
            	if (out != null) {
                    out.close();
                }
				client.close();
			} catch (IOException e) {
				logger.error("SocketTransport sendAndGetDataFromBankDL:", e);
			}
        }
		return tradeContext;
        
    }

    private int byte2int(byte[] b) throws Exception{
		String lengthS = new String(b).trim();
		if(lengthS==null || !lengthS.matches("^[0-9]+$")){
			throw new Exception("byte2int转换错误");
		}
		return  Integer.parseInt(lengthS) ;
	}
    
    private byte[] int2byte(int tmp, int bytes){
		StringBuffer tmpStr = new StringBuffer(tmp+"");
		int length = tmpStr.length();
		for(int i=0; i<bytes-length; i++){
			tmpStr.insert(0, '0');
		}
		
		return (tmpStr.toString()).getBytes();
	}
    
    public String getHost() {
        return host;
    }

    public void setHost(String host) {
        this.host = host;
    }

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }

    public int getTimeout() {
        return timeout;
    }

    public void setTimeout(int timeout) {
        this.timeout = timeout;
    }

    public int getReceiveBufferSize() {
        return receiveBufferSize;
    }

    public void setReceiveBufferSize(int receiveBufferSize) {
        this.receiveBufferSize = receiveBufferSize;
    }

    public int getSendBufferSize() {
        return sendBufferSize;
    }

    public void setSendBufferSize(int sendBufferSize) {
        this.sendBufferSize = sendBufferSize;
    }

}
